home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / StateManager / LoadSceneFromX.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  11.3 KB  |  267 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: LoadSceneFromX.cpp
  3. //
  4. // Enables the sample to build a scene from an x-file ('scene.x').
  5. // The x-file has been extended to include custom templates for specifying mesh filenames
  6. // and camera objects within frames.
  7. //
  8. // Copyright (c) Microsoft Corporation. All rights reserved.
  9. //--------------------------------------------------------------------------------------
  10.  
  11.  
  12. #include "dxstdafx.h"
  13. #include "LoadSceneFromX.h"
  14. #include <d3dx9xof.h>
  15.  
  16.  
  17. //--------------------------------------------------------------------------------------
  18. // Forward declaration 
  19. //--------------------------------------------------------------------------------------
  20. HRESULT ProcessFrame( ID3DXFileData* pFrame,
  21.                       D3DXMATRIX* pParentMatrix,
  22.                       vector<FRAMENODE>& vecFrameNodes );
  23.  
  24.  
  25. //--------------------------------------------------------------------------------------
  26. // The scene is generated from an xfile ('scene.x') that contains a hierarchy of
  27. // transformations and mesh file refernces.
  28. // Two private xfile templates are used, extending the xfile format to provide support
  29. // for such features.  These templates are found within a 'frame' datatype, which
  30. // are organized into a hierarchy.  For the purposes of this sample, the hierarchy
  31. // is immediately collapsed, as there is need to animate objects within the scene.
  32. // Template FrameMeshName includes:
  33. //      RenderPass: Default Render Pass, in which the mesh is to be rendered in
  34. //      FileName: Filename of a mesh that exists at this frame location
  35. // Template FrameCamera includes:
  36. //      RotationScaler:  Sets the speed by which the camera rotates
  37. //      MoveScaler:      Sets the speed at which the camera moves
  38. //--------------------------------------------------------------------------------------
  39. static const CHAR szTemplates[] = "xof 0303txt 0032\
  40.     template FrameMeshName { \
  41.     <c2a50aed-0ee9-4d97-8732-c14a2d8a7825> \
  42.         DWORD RenderPass;STRING FileName;} \
  43.     template FrameCamera { \
  44.     <f96e7de6-40ce-4847-b7e9-5875232e5201> \
  45.         FLOAT RotationScaler;FLOAT MoveScaler;} \
  46.     template Frame { \
  47.     <3d82ab46-62da-11cf-ab39-0020af71e433> \
  48.     [...] } \
  49.     template Matrix4x4 { \
  50.     <f6f23f45-7686-11cf-8f52-0040333594a3> \
  51.     array FLOAT matrix[16]; } \
  52.     template FrameTransformMatrix { \
  53.     <f6f23f41-7686-11cf-8f52-0040333594a3> \
  54.     Matrix4x4 frameMatrix; \
  55.     }";
  56.  
  57.  
  58. //--------------------------------------------------------------------------------------
  59. // GUIDS, corresponding to the above templates
  60. //--------------------------------------------------------------------------------------
  61. static const GUID gFrameMeshName = 
  62. { 0xc2a50aed, 0xee9, 0x4d97, { 0x87, 0x32, 0xc1, 0x4a, 0x2d, 0x8a, 0x78, 0x25 } };
  63. static const GUID gCamera = 
  64. { 0xf96e7de6, 0x40ce, 0x4847, { 0xb7, 0xe9, 0x58, 0x75, 0x23, 0x2e, 0x52, 0x1 } };
  65. static const GUID gFrameTransformMatrix =
  66. { 0xf6f23f41, 0x7686, 0x11cf, { 0x8f, 0x52, 0x0, 0x40, 0x33, 0x35, 0x94, 0xa3 } };
  67. static const GUID gFrame =
  68. { 0x3d82ab46, 0x62da, 0x11cf, { 0xab, 0x39, 0x0, 0x20, 0xaf, 0x71, 0xe4, 0x33 } };
  69.  
  70.  
  71. //--------------------------------------------------------------------------------------
  72. // Reads the scene x-file, and adds the collapsed frame hierarchy to the vecFrameNodes Hierarchy.
  73. //--------------------------------------------------------------------------------------
  74. HRESULT LoadSceneFromX( vector<FRAMENODE>& vecFrameNodes, LPWSTR wszFileName )
  75. {
  76.     HRESULT hr;
  77.  
  78.     // vecNodes will contain frames found within the x-file frame hierarchy.
  79.     vector<FRAMENODE> vecNodes;
  80.     ID3DXFile* pXFile = NULL;
  81.     ID3DXFileEnumObject* pEnum = NULL;
  82.  
  83.     // To begin reading the x-file, a ID3DXFile interface must be created
  84.     V_RETURN( D3DXFileCreate( &pXFile ) );
  85.  
  86.     // To 'understand' the x-file, templates that are used within it must be registered
  87.     V_RETURN( pXFile->RegisterTemplates( szTemplates, sizeof(szTemplates) - 1 ) );
  88.  
  89.     // Creating an ID3DXFileEnumObject allows the app to enumerate top-level data objects
  90.     V_RETURN( pXFile->CreateEnumObject( wszFileName, D3DXF_FILELOAD_FROMWFILE, &pEnum ) );
  91.     
  92.     // Because the enum object was successfully created, the ID3DXFile interface pointer can be released
  93.     SAFE_RELEASE( pXFile );
  94.  
  95.     SIZE_T toplevel_children = 0;
  96.  
  97.     // Retrieving the number of children allows the app to iterate across each child in a loop.
  98.     V_RETURN( pEnum->GetChildren( &toplevel_children ) );
  99.  
  100.     for( SIZE_T i = 0; i < toplevel_children; i++ )
  101.     {
  102.         GUID guid;
  103.         ID3DXFileData* pChild = NULL;
  104.         
  105.         // To read the data object, a pointer to its ID3DXFileData interface is obtained
  106.         V_RETURN( pEnum->GetChild( i, &pChild ) );
  107.         
  108.         // The guid corresponding to the type of the data object can be obtained via GetType.
  109.         // For the purposes of this sample, if the top-level data object is not a frame, it is ignored.
  110.         // Any frames containing mesh filename references will be added to vecFrameNodes.
  111.         V_RETURN( pChild->GetType( &guid ) );
  112.         
  113.         // Add any frames containing meshes to the vector of frames, vecFrameNodes
  114.         if( guid == gFrame )
  115.             ProcessFrame( pChild, NULL, vecFrameNodes );
  116.         
  117.         // 
  118.         SAFE_RELEASE( pChild );
  119.      }
  120.  
  121.     //
  122.     SAFE_RELEASE( pEnum );
  123.  
  124.     return S_OK;
  125. }
  126.  
  127.  
  128.  
  129. //--------------------------------------------------------------------------------------
  130. // Invoked by LoadSceneFromX - Process one frame located within the scene xfile
  131. // Reads any meshes, or cameras, that may exist within this frame.
  132. // Additionally, the frame's transform is collapsed (its matrix is concatenated with that
  133. // of it's parent).
  134. // Note: Assumes the parent node has been collapsed
  135. //--------------------------------------------------------------------------------------
  136. HRESULT ProcessFrame( ID3DXFileData* pFrame, D3DXMATRIX* pParentMatrix, vector<FRAMENODE>& vecFrameNodes )
  137. {
  138.     HRESULT hr = S_OK;
  139.  
  140.     SIZE_T children = 0;
  141.     FRAMENODE node;
  142.     
  143.     // In the event no corresponding frame transform matrix is located within the frame,
  144.     // consider it to be identity.
  145.     // Use the collapsed value of the parent matrix if it exists.
  146.     // If no parent matrix exists, this is a top-level data frame.
  147.     if( pParentMatrix )
  148.         node.mat = *pParentMatrix;
  149.     else
  150.         D3DXMatrixIdentity( &node.mat );
  151.  
  152.     // For the purposes of this sample, the frame hierarchy is collapsed in-place as each frame is encountered.
  153.     // A typical application may have a 'scene graph' arrangement of transformations, which are collapsed
  154.     // as-needed at *runtime*.  
  155.     // However, since the hierarchy *is* collaped in-place, it must be ensured that the frame's transform matrix
  156.     // has been updated and collapsed BEFORE processing child frames.
  157.     // To defer processing of child frames, they are placed into the vecChildFrames container.
  158.     vector<ID3DXFileData*> vecChildFrames;
  159.     
  160.     // Retrieving the number of children allows the app to iterate across each child in a loop.
  161.     V_RETURN( pFrame->GetChildren( &children ) );
  162.     
  163.     for( SIZE_T i = 0; i < children; i++ )
  164.     {
  165.         ID3DXFileData* pChild = NULL;
  166.         GUID guid;
  167.  
  168.         SIZE_T data_size = 0;
  169.         LPCVOID pData = NULL;
  170.  
  171.         // To read the data object, a pointer to its ID3DXFileData interface is obtained
  172.         V_RETURN( pFrame->GetChild( i, &pChild ) );
  173.         
  174.         // The guid corresponding to the type of the data object can be obtained via GetType.
  175.         V_RETURN( pChild->GetType( &guid ) );
  176.  
  177.         // The child data object is a transformation matrix -- collapse it in place, and store
  178.         // the collapsed matrix in node.mat
  179.         if( guid == gFrameTransformMatrix )
  180.         {
  181.             // ID3DXFileData::Lock allows the app to read the actual data
  182.             // If the data size of the object does not match the expectation, it is discarded
  183.             if( SUCCEEDED( hr ) && SUCCEEDED( hr = pChild->Lock( &data_size, &pData ) ) )
  184.             {
  185.                 if( sizeof(D3DXMATRIX) == data_size )
  186.                 {
  187.                     // Collapse the matrix
  188.                     // If the frame has a parent, the collapsed matrix is the product of this frame and the collapsed matrix
  189.                     // of the parent frame.
  190.                     // Otherwise, the collapsed value is the matrix itself
  191.                     if( pParentMatrix )
  192.                         D3DXMatrixMultiply( &node.mat, (D3DXMATRIX*)pData, pParentMatrix );
  193.                     else
  194.                         node.mat = *(D3DXMATRIX*)pData;
  195.                 }
  196.  
  197.                 // Having read the required data, it can now be unlocked with ID3DXFileData::Unlock
  198.                 hr = pChild->Unlock();
  199.             }
  200.         }
  201.         
  202.         // If the child data is a mesh file name, the mesh is added to the frame's MESH_REFERENCE container
  203.         else if( guid == gFrameMeshName )
  204.         {
  205.             if( SUCCEEDED( hr ) && SUCCEEDED( hr = pChild->Lock( &data_size, &pData ) ) )
  206.             {
  207.                 if( sizeof(DWORD) < data_size )
  208.                     node.meshes.push_back( MESH_REFERENCE( *(DWORD*)pData, (LPSTR)pData+4 ) );
  209.                 
  210.                 hr = pChild->Unlock();
  211.             }
  212.         }
  213.  
  214.         // Processing the children must be delayed until it can be guaranteed that any
  215.         // transform matrices have been applied. (eg, until the matrix stack has been collapsed).
  216.         else if( guid == gFrame )
  217.         {
  218.             // A child frame has been found
  219.             // Keep the data object around by adding a reference to it.
  220.             // The child will eventually be released when it is processed by iterating the container
  221.             // of child frames (vecChildFrames).
  222.             pChild->AddRef();
  223.             vecChildFrames.push_back( pChild );
  224.         }
  225.         
  226.         // A camera object was found within the frame
  227.         else if( guid == gCamera )
  228.         {
  229.             if( SUCCEEDED( hr ) && SUCCEEDED( hr = pChild->Lock( &data_size, &pData ) ) )
  230.             {
  231.                 if( 2*sizeof(FLOAT) == data_size )
  232.                     node.cameras.push_back( CAMERA_REFERENCE( *(FLOAT*)pData, *((FLOAT*)pData+1) ) );
  233.  
  234.                 hr = pChild->Unlock();
  235.             }
  236.         }
  237.  
  238.         // Now that the Child Data Object has been read, it can be released.
  239.         // Exception: child 'Frame' objects have been AddRef'd, to defer processing
  240.         SAFE_RELEASE( pChild );
  241.     }
  242.  
  243.     // Add the Frame to the collapsed node container
  244.     vecFrameNodes.push_back( node );
  245.  
  246.     // Each child frame that was deferred can now be processed
  247.     // This occurs by recursively invoking ProcessFrame, once for each child frame
  248.     for( vector<ID3DXFileData*>::iterator it = vecChildFrames.begin();
  249.          it != vecChildFrames.end();
  250.          it++
  251.          )
  252.     {
  253.         if( SUCCEEDED( hr ) )
  254.         {
  255.             // Recurse into ProcessFrame for this child
  256.             hr = ProcessFrame( *it, &node.mat, vecFrameNodes );
  257.         }
  258.  
  259.         // Done processing the child 'Frame' data object, it can be released
  260.         SAFE_RELEASE( *it );
  261.     }
  262.  
  263.     return hr;
  264. }
  265.  
  266.  
  267.